<template>
	<scroll-view class="product-info-container" @scroll="onScroll" :scroll-top="programScrollTop"
		:scroll-with-animation="true" scroll-y>
		<!-- 返回按钮（悬浮圆形按钮） -->
		<view class="back-btn" @tap="backPage">
			<up-icon name="arrow-left" size="22" color="#fff"></up-icon>
		</view>
		<!-- 顶部轮播图 -->
		<view class="banner-container">
			<swiper class="banner-swiper" circular autoplay v-if="bannerImages.length" @change="onBannerChange">
				<swiper-item v-for="(item, index) in bannerImages" :key="index">
					<image class="banner-img" :src="item.url" mode="aspectFill" />
				</swiper-item>
			</swiper>
			<!-- 如果没有轮播图，显示占位图 -->
			<view v-else class="banner-placeholder">
				<up-icon name="photo" size="60" color="#ccc" />
				<text>暂无图片</text>
			</view>
			<view class="banner-info-bar" v-if="mainInfo.productSku">

				<view class="info-item" style="margin-left: 30rpx;">
					<up-icon name="account" size="14" color="#fff" />
					<text>{{ mainInfo.productSku.minYearOld ? (mainInfo.productSku.minYearOld + '-' +
						mainInfo.productSku.maxYearOld + '岁') : '年龄范围' }}</text>
				</view>
				<view style="padding:0rpx 34rpx">|</view>
				<view class="info-item">
					<up-icon name="clock" size="14" color="#fff" />
					<text>{{ mergedItineraries.length || 0 }}天</text>
				</view>
				<view style="padding:0rpx 34rpx">|</view>
				<view class="info-item">
					<up-icon name="map" size="14" color="#fff" />
					<text>{{ mainInfo.productSku.specificItinerary?.[0]?.items?.[0]?.address?.split('市')[0] + '市' ||
						'暂无地址' }}</text>
				</view>

				<!-- 轮播图下方信息条 -->
				<view class="info-item" style="display: flex;justify-content: flex-end;flex:1;padding-right: 30rpx;">
					<text class="current">{{ activeIndex }}</text>
					<text class="split">/</text>
					<text class="total">{{ bannerImages.length }}</text>
				</view>
			</view>
		</view>
		<!-- 产品标题 -->
		<view class="container-card">
			<view class="title-container" id="title-container" v-if="!stickyTitle">
				<view class="title">{{ mainInfo.productSpu?.name || '暂无产品标题' }}</view>
				<!-- 渠道标签和价格 -->
				<view class="channel-price-tag">
					<view class="channel-tag">郑州二七接送</view>
					<text class="channel-text">渠道 ¥ <text class="price-integer">{{ priceInteger }}</text><text
							class="price-decimal">.{{ priceDecimal }}</text> CNY</text>
				</view>
			</view>
			<AdaptiveNavBar title="产品预览" text-color="#333333" backgroundColor="#ffffff" v-else />
			<!-- 产品标题占位元素，避免吸顶时内容跳动 -->
			<view v-if="stickyTitle" class="title-placeholder"></view>

			<!-- 导航栏锚点：用于计算吸顶阈值（初始不显示导航，仅作为位置参考） -->
			<view id="nav-anchor"></view>

			<!-- 导航栏（仅吸顶时显示） -->
			<view v-if="stickyNav" class="nav-container sticky-nav" id="nav-container"
				:style="{ top: titleHeightPx + 'px' }">
				<view class="nav-item" v-for="(item, index) in navItems" :key="index"
					:class="{ 'active': activeNavIndex === index }" @tap="scrollToSection(item.id)">
					<text>{{ item.name }}</text>
				</view>
			</view>
			<!-- 导航栏占位元素，避免吸顶时内容跳动 -->
			<view v-if="stickyNav" class="nav-placeholder"></view>

			<!-- 卡片：罗列展示 -->
			<!-- 产品特色 -->
			<view class="card" id="features-section" style="padding: 30rpx 0rpx;">
				<view class="section-title">
					<text>产品特色</text>
				</view>
				<view class="card-content" style="padding: 20rpx 0rpx;">
					<view v-if="mergedFeatures?.length">
						<!-- 特色内容容器，根据展开状态控制高度 -->
						<view class="features-container" :class="{ 'collapsed': !cardFoldStates.features }">
							<view v-for="(item, index) in mergedFeatures" :key="index" class="feature-item">
								<!-- 显示图片（如果有） -->
								<image v-if="item.imgUrl" :src="item.imgUrl" class="feature-image" mode="widthFix" />
								<!-- 显示文本内容（过滤掉"产品特色图片"文字） -->
								<text v-if="item.alt && item.alt !== '产品特色图片'" class="feature-text">{{ item.alt
									}}</text>
							</view>
						</view>
						<!-- 展开/收起按钮 -->
						<view class="expand-btn" @tap="toggleCard('features')">
							<text class="expand-text">{{ cardFoldStates.features ? '收起' : '展开' }}</text>
							<up-icon :name="cardFoldStates.features ? 'arrow-up' : 'arrow-down'" size="16"
								color="#999" />
						</view>
					</view>
					<view v-else class="empty-content">暂无产品特色</view>
				</view>
			</view>
			<!-- 具体行程 -->
			<view class="card" id="itinerary-section" style="padding:30rpx 0rpx">
				<view class="card-header">
					<view class="section-title">
						<text>具体行程</text>
					</view>
				</view>
				<view class="card-content" style="padding: 20rpx 0rpx;">
					<view v-if="mergedItineraries?.length">
						<view v-for="(dayItem, index) in mergedItineraries" :key="index" class="day-item">
							<!-- 每一天的头部 -->
							<view class="day-header" @tap="toggleDay(index)">
								<view class="day-badge">D{{ dayItem.day }}</view>
								<view class="day-content">
									<text class="day-title">{{ dayItem.main || '行程安排' }}</text>
								</view>
								<image class="day-arrow-icon" :class="{ 'day-arrow-rotated': dayItem.show }"
									src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
							</view>

							<!-- 子项目列表 -->
							<view v-if="dayItem.show" class="day-details">
								<view class="activity-list">
									<view v-for="(item, itemIndex) in dayItem.items" :key="itemIndex"
										class="itinerary-detail-item">
										<view class="item-time-container">
											<text class="item-time">{{ item.startTime || '10:30' }}</text>
											<text class="item-type">{{ item.title || '活动' }}</text>
											<text class="item-separator">|</text>
											<text class="item-name">{{ item.name || item.alt || '未填写标题' }}</text>
										</view>

										<view class="item-details">
											<view class="item-detail-row">
												<view class="detail-label">
													<img class="detail-label-icon"
														src="../../static/systemIcon/time.png" alt="">
												</view>
												<text class="detail-value">{{ item.startTime }} - {{ item.endTime
													}}</text>
											</view>
											<view class="item-detail-row">
												<view class="detail-label">
													<img class="detail-label-icon"
														src="../../static/systemIcon/address.png" alt="">
												</view>
												<view class="detail-value address-display">
													<text v-if="getAddressName(item.address)" class="address-name">{{
														getAddressName(item.address) }}</text>
													<text v-if="getAddressLocation(item.address)"
														class="address-location">{{
															getAddressLocation(item.address) }}</text>
												</view>
											</view>
											<view class="item-detail-row" v-if="item.description">
												<view class="detail-label">
													<img class="detail-label-icon"
														src="../../static/systemIcon/introduction.png" alt="">
												</view>
												<text class="detail-value">{{ item.description }}</text>
											</view>
										</view>
									</view>
								</view>
							</view>
						</view>
					</view>
					<view v-else class="empty-content">暂无行程安排</view>
				</view>
			</view>
			<!-- 服务详情 -->
			<view class="card" id="service-section">
				<view class="card-header" @tap="toggleCard('service')">
					<view class="section-title-with-lines">
						<view class="title-line"></view>
						<text class="title-text">服务详情</text>
						<view class="title-line"></view>
					</view>
				</view>
				<view class="card-content">
					<!-- 费用包含模块 -->
					<view class="expense-section">
						<view class="expense-title">费用包含</view>
						<view v-if="mainInfo.productSku?.expensesIncluded?.length">
							<view v-for="(service, i) in mainInfo.productSku.expensesIncluded" :key="i"
								class="info-row">
								<text class="label">{{ service.title }}</text>
								<text class="value">{{ service.alt }}</text>
							</view>
						</view>
					</view>

					<!-- 分隔线 -->
					<view class="expense-divider"></view>

					<!-- 费用不含模块 -->
					<view class="expense-section">
						<view class="expense-title">费用不含</view>
						<view v-if="mainInfo.productSku?.expensesExcluded">
							<view class="info-row">

								<text class="value">{{ mainInfo.productSku.expensesExcluded }}</text>
							</view>
						</view>
					</view>

					<!-- 分隔线 -->
					<view class="expense-divider"></view>

					<!-- 另付费项目模块 -->
					<view class="expense-section">
						<view class="expense-title">另付费项目</view>
						<view v-if="mainInfo.productSku?.otherExpenses">
							<view class="info-row">
								<text class="value">{{ mainInfo.productSku.otherExpenses }}</text>
							</view>
						</view>
					</view>

					<view
						v-if="!mainInfo.productSku?.expensesIncluded?.length && !mainInfo.productSku?.expensesExcluded?.length && !mainInfo.productSku?.otherExpenses?.length"
						class="empty-content">暂无服务详情</view>
				</view>
			</view>

			<!-- 服务详情 -->
			<view class="card" id="service-section">
				<view class="card-header" @tap="toggleCard('service')" style="padding: 0rpx 16rpx;">
					<view class="section-title-with-lines" style="justify-content: flex-start;padding-top: 0rpx;">
						<text class="server-title">服务商信息</text>
					</view>
					<view class="serve-box">
						<view class="serve-title">
							目的地接待:
						</view>
						<view class="serve-content">
							<view>郑州XXXX旅行社有限公司</view>
							<view>L-HEN-CJ8888888测试</view>
						</view>
					</view>
					<view class="serve-box">
						<view class="serve-title">
							组团及服务:
						</view>
						<view class="serve-content">
							<view>郑州XXXX旅行社有限公司</view>
							<view>L-HEN-CJ8888888测试</view>
						</view>
					</view>
					<view class="serve-box">
						<view class="serve-title">
							随队及服务:
						</view>
						<view class="serve-content">
							<view>郑州XXXX旅行社有限公司</view>
							<view>L-HEN-CJ8888888测试</view>
						</view>
					</view>
				</view>

			</view>

			<!-- 预定须知 -->
			<view class="card" id="notice-section">
				<view class="card-header">
					<view class="section-title-with-lines">
						<view class="title-line"></view>
						<text class="title-text">预定须知</text>
						<view class="title-line"></view>
					</view>
				</view>
				<view class="card-content">
					<!-- 预定限制模块 -->
					<view class="expense-section">
						<view class="expense-header">
							<view class="expense-title">预定限制</view>
							<image class="notice-arrow-icon" :class="{ 'notice-arrow-rotated': noticeItemStates.basic }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="noticeItemStates.basic" class="expense-content">
							<view class="info-row" style="flex-direction: column;">
								<view class="value">适用年龄范围: {{ Number(mainInfo.productSku?.minYearOld) }}岁-{{
									Number(mainInfo.productSku?.maxYearOld) }}岁</view>
								<view class="value">本产品{{ mainInfo.productSku.parentsAccompanied == 0 ? '不支持' : '支持' }}家长陪同
								</view>
							</view>
						</view>
					</view>

					<!-- 分隔线：判断是否还有后续内容 -->
					<view class="expense-divider"
						v-if="mainInfo.productSku.guaranteePrompt?.length || mainInfo.productSku.riskPrompt?.length || mainInfo.productSku.customizationPrompt?.length || shouldShowGroupRules()">
					</view>

					<!-- 保障提示模块 -->
					<view class="expense-section" v-if="mainInfo.productSku.guaranteePrompt?.length">
						<view class="expense-header">
							<view class="expense-title">保障提示</view>
							<image class="notice-arrow-icon"
								:class="{ 'notice-arrow-rotated': noticeItemStates.guarantee }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="noticeItemStates.guarantee" class="expense-content">
							<view class="info-row">
								<view :key="index">
									<text class="value">{{
										'为切实履行好普通消费者权益保护等方面的义务，纤程旅行会基于安全和公平交易原则对包括但不限于扰乱系统、网络攻击、刷单、倒卖、转售订单及包括但不限于注册账号、用户信息、交易数量存在异常的订单进行风险交易判定，此部分不符合交易安全和公平原则的订单纤程旅行有权采取警示、暂停或者终止服务等措施且不承担因此原因取消订单的任何责任。'
										}}</text>
								</view>
							</view>
						</view>
					</view>

					<!-- 分隔线：判断是否还有后续内容 -->
					<view class="expense-divider"
						v-if="mainInfo.productSku.guaranteePrompt?.length && (mainInfo.productSku.riskPrompt?.length || mainInfo.productSku.customizationPrompt?.length || shouldShowGroupRules())">
					</view>

					<!-- 风险提示模块 -->
					<view class="expense-section" v-if="mainInfo.productSku.riskPrompt?.length">
						<view class="expense-header" @tap="toggleNoticeItem('risk')">
							<view class="expense-title">风险提示</view>
							<image class="notice-arrow-icon" :class="{ 'notice-arrow-rotated': noticeItemStates.risk }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="noticeItemStates.risk" class="expense-content">
							<view v-if="Array.isArray(mainInfo.productSku.riskPrompt)" class="info-row">
								<view v-for="(item, index) in mainInfo.productSku.riskPrompt" :key="index">
									<text class="value">{{ item.alt }}</text>
								</view>
							</view>
							<view v-else class="info-row">
								<text class="value">{{ mainInfo.productSku.riskPrompt }}</text>
							</view>
						</view>
					</view>

					<!-- 分隔线：判断是否还有后续内容 -->
					<view class="expense-divider"
						v-if="mainInfo.productSku.riskPrompt?.length && (mainInfo.productSku.customizationPrompt?.length || shouldShowGroupRules())">
					</view>

					<!-- 自定义提示模块（数组拆开逐条渲染，样式与风险提示一致） -->
					<template
						v-if="Array.isArray(mainInfo.productSku.customizationPrompt) && mainInfo.productSku.customizationPrompt.length">
						<template v-for="(cp, cIdx) in mainInfo.productSku.customizationPrompt" :key="cIdx">
							<view class="expense-section">
								<view class="expense-header" @tap="toggleCustomizationItem(cIdx)">
									<view class="expense-title">{{ cp.title }}</view>
									<image class="notice-arrow-icon"
										:class="{ 'notice-arrow-rotated': noticeItemStates['customization_' + cIdx] }"
										src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
								</view>
								<view v-if="noticeItemStates['customization_' + cIdx]" class="expense-content">
									<view class="info-row">
										<text class="value">{{ cp.alt }}</text>
									</view>
								</view>
							</view>
							<!-- 分隔线：自定义数组内部的分隔线 -->
							<view class="expense-divider"
								v-if="cIdx != (mainInfo.productSku.customizationPrompt.length - 1)"></view>
						</template>
					</template>

					<!-- 分隔线：判断是否还有后续内容 -->
					<view class="expense-divider"
						v-if="mainInfo.productSku.customizationPrompt?.length && shouldShowGroupRules()"></view>

					<!-- 成团说明模块 -->
					<view class="expense-section" v-if="shouldShowGroupRules()">
						<view class="expense-header" @tap="toggleTermsItem('group')">
							<view class="expense-title">成团说明</view>
							<image class="notice-arrow-icon" :class="{ 'notice-arrow-rotated': termsItemStates.group }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="termsItemStates.group" class="expense-content">
							<view class="info-row">
								<text class="value">{{ mainInfo.productSku?.groupRules?.groupDescription ||
									'本次旅游团人数为15人起，报名后将根据人数确认出发日期，确保旅行质量。若人数未达成团要求，将提供退款或调整出发时间的选项。团员需按时缴纳费用，确保顺利成行。'
									}}</text>
							</view>
						</view>
					</view>

					<!-- 退团规则模块 -->
					<view class="expense-section" v-if="shouldShowGroupRules()">
						<!-- 分隔线：判断是否还有后续内容 -->
						<view class="expense-divider" v-if="shouldShowGroupRules()"></view>
						<view class="expense-header" @tap="toggleTermsItem('refund')">
							<view class="expense-title">退团规则</view>
							<image class="notice-arrow-icon" :class="{ 'notice-arrow-rotated': termsItemStates.refund }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="termsItemStates.refund" class="expense-content">
							<view class="info-row">
								<text class="value">{{ mainInfo.productSku?.groupRules?.refundRules ||
									'出发前7天内申请退团，按已支付费用的80%退还；出发前3天内申请退团，按已支付费用的50%退还；出发前1天内申请退团，恕不退还费用。特殊情况下可提供部分退款或改期服务，具体以实际情况为准，退团需提供书面申请。'
									}}</text>
							</view>
						</view>
					</view>

					<!-- 违约条款模块 -->
					<view class="expense-section" v-if="shouldShowGroupRules()">
						<!-- 分隔线：判断是否还有后续内容 -->
						<view class="expense-divider" v-if="shouldShowGroupRules()"></view>
						<view class="expense-header" @tap="toggleTermsItem('breach')">
							<view class="expense-title">违约条款</view>
							<image class="notice-arrow-icon" :class="{ 'notice-arrow-rotated': termsItemStates.breach }"
								src="/static/systemIcon/arrow-bottom.png" mode="aspectFit" />
						</view>
						<view v-if="termsItemStates.breach" class="expense-content">
							<view class="info-row">
								<text class="value">{{ mainInfo.productSku?.groupRules?.breachClause ||
									'若游客未按约定时间参加旅行或提前终止行程，将根据实际损失收取相应违约金。若因不可抗力因素导致旅行无法成行，按合同约定提供全额退款或改期服务。违约行为需承担因此产生的费用。'
									}}</text>
							</view>
						</view>
					</view>

					<!-- 判断是否有任何内容（这里已经有预定限制模块了） -->
					<view
						v-if="!mainInfo.productSku.guaranteePrompt?.length && !mainInfo.productSku.riskPrompt?.length && !mainInfo.productSku.customizationPrompt?.length && !shouldShowGroupRules()"
						class="empty-content" style="padding: 20rpx 0rpx;">暂无其他预定须知</view>
				</view>
			</view>

			<!-- 预览页面提示 -->
			<view class="preview-notice">
				<view class="preview-icon">
					<up-icon name="eye" size="24" color="#ff6700" />
				</view>
				<view class="preview-text">
					<text class="preview-title">预览模式</text>
					<text class="preview-desc">此页面仅用于预览产品效果，非正式产品页面</text>
				</view>
				<view class="exit-preview-btn" v-if="isPreviewMode" @tap="exitPreview">退出预览</view>
			</view>
		</view>

	</scroll-view>

</template>

<script>
import DateCard from '@/components/DateCard';
import GlobalTopNav from '@/components/GlobalTopNav';
export default {
	name: 'ProductInfo',
	components: {
		DateCard,
		GlobalTopNav
	},
	data() {
		return {
			// 页面基本数据
			activeIndex: 1,
			// 预览模式标识
			isPreviewMode: false,
			// 产品数据
			mainInfo: {},
			mergedFeatures: [],
			mergedItineraries: [],
			// 性能优化相关
			scrollTimer: null, // 滚动节流定时器
			sectionPositions: [], // 缓存区域位置信息
			lastScrollTop: 0, // 上次滚动位置
			// 胶囊按钮（右上角三点菜单）相关
			menuButtonInfo: null,
			capsuleBottomPx: 0,
			capsuleTopPx: 0,
			capsuleHeightPx: 0,
			// 缓存计算结果，避免频繁计算
			cachedTitleHeightPx: 0,
			cachedNavHeightPx: 0,
			isScrollingToTarget: false, // 是否正在执行滚动到目标位置的动画
			pendingTargetIndex: -1, // 程序滚动时期望激活的导航索引

			// 其他状态
			isFold: false,
			swiperCurrent: 0,
			mode: '',

			// 页面参数
			id: '', // spuId
			originCompanyInfo: {},
			companyInfo: {},
			price: 0,

			// 安全区域
			safeAreaInsets: {},

			// 卡片折叠状态
			cardFoldStates: {
				features: false,      // 产品特色 - false表示半展开状态，true表示完全展开
				itinerary: true,     // 具体行程
				service: true,       // 服务详情
				notice: true,        // 预定须知
				terms: true          // 成团/退团/违约条款
			},

			// 预定须知项目展开状态
			noticeItemStates: {
				basic: true,        // 预定须知基础信息
				guarantee: true,    // 保障提示
				risk: false,         // 风险提示
				customization: false // 自定义提示
			},

			// 条款项目展开状态
			termsItemStates: {
				group: false,        // 成团说明
				refund: false,       // 退团规则
				breach: false        // 违约条款
			},

			// 吸顶相关
			stickyTitle: false,       // 产品标题是否吸顶
			stickyNav: false,         // 导航栏是否吸顶
			activeNavIndex: 0,        // 当前激活的导航项索引
			scrollTop: 0,             // 滚动位置（记录用）
			programScrollTop: 0,      // 程序控制的滚动位置（用于绑定）
			titleOriginalTop: 0,      // 产品标题原始位置
			navOriginalTop: 0,        // 导航栏原始位置
			navItems: [               // 导航项配置
				{ name: '产品特色', id: 'features-section' },
				{ name: '具体行程', id: 'itinerary-section' },
				{ name: '服务详情', id: 'service-section' },
				{ name: '预定须知', id: 'notice-section' },
			],
			businessType: uni.getStorageSync('companyInfo').businessType,
			businessEntry: uni.getStorageSync('businessEntry'), // 入口标识
		};
	},
	computed: {
		// 轮播图图片列表
		bannerImages() {
			// 优先使用 productSku.images
			if (this.mainInfo.productSku?.images?.length) {
				return this.mainInfo.productSku.images;
			}
			// 如果没有，尝试使用 productSpu.images
			if (this.mainInfo.productSpu?.images?.length) {
				return this.mainInfo.productSpu.images;
			}
			// 如果都没有，尝试使用 mainImage 作为单张图片
			if (this.mainInfo.productSpu?.mainImage) {
				return [{ url: this.mainInfo.productSpu.mainImage }];
			}
			// 都没有，返回空数组
			return [];
		},
		// 标题高度（rpx->px）- 使用缓存
		titleHeightPx() {
			if (this.$navbarUtil && this.$navbarUtil.getNavbarTotalHeight) {
				const h = this.$navbarUtil.getNavbarTotalHeight();
				if (typeof h === 'number' && h > 0) return h;
			}
			return this.cachedTitleHeightPx || this.rpxToPx(160);
		},
		// 导航高度（rpx->px）- 使用缓存
		navHeightPx() {
			return this.cachedNavHeightPx || this.rpxToPx(80);
		},
		// 价格整数部分
		priceInteger() {
			const price = this.mainInfo.price || 0;
			return Math.floor(price);
		},
		// 价格小数部分
		priceDecimal() {
			const price = this.mainInfo.price || 0;
			const decimal = (price % 1).toFixed(2).substring(2);
			return decimal;
		}
	},
	onLoad(options) {
		console.log('options:', options);
		console.log('缓存', uni.getStorageInfoSync('companyInfo'))
		const { safeAreaInsets } = uni.getSystemInfoSync()
		// 存储安全区域信息
		this.safeAreaInsets = safeAreaInsets;
		console.log('safeAreaInsets', safeAreaInsets)
		// 获取胶囊按钮信息并计算位置（px）
		try {
			const info = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect();
			this.menuButtonInfo = info || null;
			this.capsuleBottomPx = info && info.bottom ? info.bottom : 0;
			this.capsuleTopPx = info && info.top ? info.top : 0;
			this.capsuleHeightPx = info && info.height ? info.height : 0;
			console.log('胶囊按钮信息:', info, 'top:', this.capsuleTopPx, 'bottom:', this.capsuleBottomPx, 'height:', this.capsuleHeightPx);
		} catch (err) {
			console.warn('获取胶囊按钮信息失败:', err);
			this.menuButtonInfo = null;
			this.capsuleBottomPx = 0;
			this.capsuleTopPx = 0;
			this.capsuleHeightPx = 0;
		}

		// 缓存高度计算结果：使用自适应导航栏总高度，统一 px 基准
		this.cachedTitleHeightPx = this.getNavbarHeightPx();
		this.cachedNavHeightPx = this.rpxToPx(80);

		// 预览模式：从存储中读取数据
		try {
			const previewData = uni.getStorageSync('previewData');
			if (previewData) {
				console.log('从存储中读取预览数据:', previewData);
				this.loadPreviewData(previewData);
				// 清理存储的预览数据
				uni.removeStorageSync('previewData');
			} else {
				console.error('未找到预览数据');
				uni.showToast({
					title: '预览数据不存在',
					icon: 'none'
				});
			}
		} catch (error) {
			console.error('读取预览数据失败:', error);
			uni.showToast({
				title: '预览数据读取失败',
				icon: 'none'
			});
		}

	},
	onReady() {
		this.initElementPositions()
	},
	// 页面卸载时清理定时器
	onUnload() {
		if (this.scrollTimer) {
			clearTimeout(this.scrollTimer);
			this.scrollTimer = null;
		}
	},
	methods: {
		shouldShowGroupRules() {
			const isBusinessType2 = (this.businessType === 2 || this.businessType === 3);
			// 目的地接待业务的入口标识：dest_receive
			const isDestinationReception = this.businessEntry === 'dest_receive'
				|| this.businessEntry === '目的地接待业务'
				|| this.businessEntry === 'destination_reception'
				|| this.businessEntry === 'destinationReception'
				|| this.businessEntry?.includes('目的地接待')
				|| this.businessEntry?.includes('接待');



			// 必须是二类商家
			if (!isBusinessType2) {
				//('不是二类商家，不显示成团条款');
				return false;
			}
			// 如果入口标识是"目的地接待业务"（dest_receive），则不显示
			if (isDestinationReception) {
				//('是目的地接待业务入口，不显示成团条款');
				return false;
			}
			//('显示成团条款');
			return true;
		},
		// rpx 转 px
		rpxToPx(rpx) {
			const systemInfo = uni.getSystemInfoSync();
			const screenWidth = systemInfo.screenWidth || 375;
			return (rpx * screenWidth) / 750;
		},

		// 获取自适应导航栏高度（px），兼容不同机型
		getNavbarHeightPx() {
			try {
				const h = this.$navbarUtil && this.$navbarUtil.getNavbarTotalHeightRpx && this.$navbarUtil.getNavbarTotalHeightRpx();
				let rpxVal = 160;
				if (typeof h === 'number') {
					rpxVal = h;
				} else if (typeof h === 'string') {
					const m = h.match(/\d+/);
					rpxVal = m ? parseInt(m[0], 10) : 160;
				}
				return this.rpxToPx(rpxVal);
			} catch (e) {
				return this.rpxToPx(160);
			}
		},

		// 加载预览数据
		loadPreviewData(previewData) {
			console.log('加载预览数据:', previewData);

			// 设置预览模式标识
			this.isPreviewMode = true;
			let customizationPrompt = [];
			const cp = previewData.customizationPrompt;
			if (Array.isArray(cp)) {
				customizationPrompt = cp;
			} else if (typeof cp === 'string') {
				const trimmed = cp.trim();
				if (trimmed && trimmed !== '[]') {
					try {
						const parsed = JSON.parse(trimmed);
						customizationPrompt = Array.isArray(parsed) ? parsed : [];
					} catch (e) {
						customizationPrompt = [];
					}
				} else {
					customizationPrompt = [];
				}
			}

			// 费用包含/不含：统一处理数组与字符串，字符串字段取数组第一个元素的 alt
			let includedArray = [];
			let includedStr = '';
			if (Array.isArray(previewData.expensesIncluded)) {
				includedArray = previewData.expensesIncluded;
				includedStr = (previewData.expensesIncluded[0] && (previewData.expensesIncluded[0].alt || previewData.expensesIncluded[0].content)) || '';
			} else if (typeof previewData.expensesIncluded === 'string') {
				includedArray = previewData.expensesIncluded.trim() ? [{ title: '费用包含', alt: previewData.expensesIncluded.trim() }] : [];
				includedStr = previewData.expensesIncluded;
			}

			let excludedStr = '';
			if (Array.isArray(previewData.expensesExcluded)) {
				excludedStr = (previewData.expensesExcluded[0] && (previewData.expensesExcluded[0].alt || previewData.expensesExcluded[0].content)) || '';
			} else if (typeof previewData.expensesExcluded === 'string') {
				excludedStr = previewData.expensesExcluded;
			}

			let otherStr = '';
			if (Array.isArray(previewData.otherExpenses)) {
				otherStr = (previewData.otherExpenses[0] && (previewData.otherExpenses[0].alt || previewData.otherExpenses[0].content)) || '';
			} else if (typeof previewData.otherExpenses === 'string') {
				otherStr = previewData.otherExpenses;
			}
			// 构建完整的 mainInfo 数据结构
			this.mainInfo = {
				productSpu: {
					name: previewData.productName || '预览产品',
					// 其他产品基本信息
				},
				productSku: {
					// 产品详细信息
					minYearOld: previewData.minYearOld || 6,
					maxYearOld: previewData.maxYearOld || 18,
					parentsAccompanied: previewData.parentsAccompanied || 0,
					guaranteePrompt: this.convertToArrayFormat(previewData.guaranteePrompt, '保障提示'),
					riskPrompt: this.convertToArrayFormat(previewData.riskPrompt, '风险提示'),
					customizationPrompt: customizationPrompt,
					groupRules: {
						groupFormation: previewData.groupFormation || '成团说明：本次旅游团人数为24人起，如未达到成团人数，将提前3天通知并全额退款。',
						refundRules: previewData.refundRules || '退团规则：出发前7天内申请退团，扣除30%费用；出发前3天内申请退团，扣除50%费用。',
						breachClause: previewData.breachClause || '违约条款：若游客未按约定时间参加旅行或提前终止行程，将根据实际损失收取相应违约金。'
					},
					bookingInfo: previewData.bookingInfo || '请提前3天预订，预订成功后不可取消。如需改期，请提前24小时联系客服。',
					specificItinerary: previewData.specificItinerary || [],

					// 轮播图数据
					images: previewData.images && previewData.images.length > 0 ?
						previewData.images.map(img => ({
							url: img.url || img,
							alt: img.alt || '',
							order: img.order || 0,
							width: img.width || 0,
							height: img.height || 0
						})) : [],

					// 产品特色数据（转换后的数组）
					productFeatures: previewData.productFeatures,

					// 费用信息
					expensesIncluded: includedArray,
					expensesExcluded: excludedStr,
					otherExpenses: otherStr
				},
				price: previewData.price || 0.00
			};

			// 设置班期数据到外层（因为班期选择组件需要）
			if (previewData.dateList && previewData.dateList.length > 0) {
				this.datelist = previewData.dateList;
				this.displayDateList = this.datelist.slice(0, this.maxDisplayDates);
			} else {
				// 默认班期数据
				this.datelist = [
					{
						id: '1',
						DateName: '2024-01-15',
						price: previewData.price || 1580.00,
						stock: 20
					}
				];
				this.displayDateList = this.datelist;
			}

			// 从 mainInfo 中同步数据到外层变量（为了兼容现有代码）
			// 🔑 将 productFeatures 和 addProductFeatures 拼接
			const productFeatures = this.mainInfo.productSku.productFeatures || [];
			const addProductFeatures = this.mainInfo.productSku.addProductFeatures || [];
			this.mergedFeatures = [...productFeatures, ...addProductFeatures];
			this.mergedItineraries = this.mainInfo.productSku.specificItinerary || [];
			this.expensesIncluded = this.mainInfo.productSku.expensesIncluded || [];
			this.expensesExcluded = this.mainInfo.productSku.expensesExcluded || [];
			this.otherExpenses = this.mainInfo.productSku.otherExpenses || [];

			console.log('预览数据加载完成:', this.mainInfo);
			console.log('轮播图数据:', this.mainInfo.productSku.images);
			console.log('产品特色数据:', this.mainInfo.productSku.productFeatures);
			console.log('产品特色数据详情:', JSON.stringify(this.mainInfo.productSku.productFeatures, null, 2));
		},

		// 将数据转换为数组格式（兼容字符串和数组）
		convertToArrayFormat(data, defaultTitle) {
			if (!data) {
				return [];
			}

			// 如果已经是数组，直接返回
			if (Array.isArray(data)) {
				return data;
			}

			// 如果是字符串，转换为数组格式
			if (typeof data === 'string' && data.trim()) {
				return [{
					title: defaultTitle,
					alt: data.trim(),
					id: 1
				}];
			}

			return [];
		},

		// 将 HTML 内容转换成产品特色数组
		convertHtmlToFeaturesArray(htmlContent) {
			if (!htmlContent || typeof htmlContent !== 'string') {
				return [];
			}

			try {
				// 解析 HTML 内容
				const features = [];
				let order = 1;

				// 使用正则表达式匹配图片标签和文本内容
				// 匹配 <img> 标签
				const imgRegex = /<img[^>]+src="([^"]+)"[^>]*>/gi;
				// 匹配文本内容（去除 HTML 标签）
				const textRegex = /<[^>]*>/g;

				// 按行分割内容
				const lines = htmlContent.split(/<br\s*\/?>|<p[^>]*>|<\/p>/i);

				lines.forEach(line => {
					const trimmedLine = line.trim();
					if (!trimmedLine) return;

					// 检查是否包含图片
					const imgMatch = imgRegex.exec(trimmedLine);
					if (imgMatch) {
						// 提取图片 URL
						const imageUrl = imgMatch[1];

						// 提取文本内容（去除 HTML 标签）
						const textContent = trimmedLine.replace(textRegex, '').trim();

						features.push({
							image: imageUrl,
							order: order++,
							alt: textContent || '',
							type: 'image'
						});
					} else {
						// 纯文本内容
						const textContent = trimmedLine.replace(textRegex, '').trim();
						if (textContent) {
							features.push({
								image: '',
								order: order++,
								alt: textContent,
								type: 'text'
							});
						}
					}
				});

				// 如果没有找到任何内容，尝试其他解析方式
				if (features.length === 0) {
					// 尝试直接匹配所有图片
					let match;
					imgRegex.lastIndex = 0; // 重置正则表达式
					while ((match = imgRegex.exec(htmlContent)) !== null) {
						features.push({
							image: match[1],
							order: order++,
							alt: '',
							type: 'image'
						});
					}
				}

				return features;
			} catch (error) {
				console.error('解析产品特色 HTML 失败:', error);
				return [];
			}
		},
		//轮播图变化
		onBannerChange(e) {
			this.activeIndex = e.detail.current + 1
		},

		// 获取公司信息
		async getCompanyInfo() {
			try {
				console.log('获取商家信息 - SpuId:', this.id);

				// 检查spuId是否存在
				if (!this.id) {
					console.error('spuId不存在，无法获取商家信息');
					// 不阻塞页面加载，只是提示
					setTimeout(() => {
						uni.showToast({
							title: '产品ID不存在',
							icon: 'none'
						});
					}, 500);
					return;
				}

				const res = await request({
					url: `/merchant/getMerchant?spuId=${this.id}`,
					method: 'GET',
					loading: false // 关闭loading，避免阻塞
				});

				console.log('商家信息响应:', res);

				if (res.code === 200 && res.data) {
					this.originCompanyInfo = res.data;
					console.log('商家信息获取成功:', this.originCompanyInfo);
					// 继续获取班期信息
					this.getPeriod();
				} else {
					console.error('获取商家信息失败 - 响应码:', res.code, '消息:', res.message);
					// 延迟显示提示，不阻塞页面
					setTimeout(() => {
						uni.showToast({
							title: res.message || '获取公司信息失败',
							icon: 'none',
							duration: 2000
						});
					}, 500);
				}
			} catch (error) {
				console.error('获取公司信息网络错误:', error);
				// 延迟显示提示，不阻塞页面
				setTimeout(() => {
					uni.showToast({
						title: '网络异常，请重试',
						icon: 'none',
						duration: 2000
					});
				}, 500);
			}
		},





		// 初始化元素位置
		initElementPositions() {
			const query = uni.createSelectorQuery().in(this);

			// 获取产品标题容器的位置
			query.select('#title-container').boundingClientRect((rect) => {
				console.log('产品', rect)
				if (rect) {
					this.titleOriginalTop = rect.top + this.scrollTop;
					console.log('产品标题原始位置:', this.titleOriginalTop);
				}
			});

			// 获取导航栏锚点的位置（用于吸顶阈值计算）
			query.select('#nav-anchor').boundingClientRect((rect) => {
				console.log('导航栏', rect)
				if (rect) {
					this.navOriginalTop = rect.top + this.scrollTop;
					console.log('导航栏原始位置:', this.navOriginalTop);
				}
			});

			// 缓存所有区域的位置信息，避免频繁查询
			this.cacheSectionPositions();

			query.exec();
		},

		// 缓存区域位置信息
		cacheSectionPositions() {
			const query = uni.createSelectorQuery().in(this);
			const sectionIds = this.navItems.map(item => item.id);

			query.selectAll(sectionIds.map(id => `#${id}`).join(',')).boundingClientRect((rects) => {
				if (rects && rects.length > 0) {
					this.sectionPositions = rects.map((rect, index) => ({
						id: sectionIds[index],
						top: rect ? rect.top + this.scrollTop : 0,
						height: rect ? rect.height : 0
					}));
					console.log('缓存区域位置:', this.sectionPositions);
				}
			});
			query.exec();
		},







		// 获取班期价格
		getPeriodPrice(date) {
			if (!this.periodList || this.periodList.length === 0) {
				return 0;
			}

			const dateStr = date.DateName.split('-');
			let totalPrice = 0;

			// 查找对应的p3价格
			if (this.periodList[0].p3s) {
				const period3 = this.periodList[0].p3s.find(item => item.id === date.id);
				if (period3) {
					totalPrice += period3.price || 0;
				}
			}

			// 查找对应的p2价格
			if (this.periodList[0].p2s) {
				const period2 = this.periodList[0].p2s.find(item =>
					item.availableDate.yearDate === dateStr[0] &&
					item.availableDate.monthDate === dateStr[1] &&
					item.availableDate.dayDate === dateStr[2]
				);
				if (period2) {
					totalPrice += period2.price || 0;
				}
			}

			// 查找对应的p1价格
			if (this.periodList[0].p1s) {
				const period1 = this.periodList[0].p1s.find(item =>
					item.availableDate.yearDate === dateStr[0] &&
					item.availableDate.monthDate === dateStr[1] &&
					item.availableDate.dayDate === dateStr[2]
				);
				if (period1) {
					totalPrice += period1.price || 0;
				}
			}

			return totalPrice;
		},

		formatDate(val) {
			if (!val) return '';
			if (typeof val === 'string') {
				return val.split(' ')[0]; // 保留日期
			}
			if (val instanceof Date) {
				return val.toISOString().slice(0, 19).replace('T', ' ');
			}
			return val;
		},

		// 格式化时间为HH:MM格式
		formatTime(val) {
			if (!val) return '';
			if (typeof val === 'string') {
				// 如果是完整的时间字符串，提取时间部分
				const timeMatch = val.match(/(\d{2}:\d{2})/);
				return timeMatch ? timeMatch[1] : val;
			}
			return val;
		},

		// 根据活动标题获取图标
		getActivityIcon(title) {
			if (!title) return '●';
			const titleLower = title.toLowerCase();
			if (titleLower.includes('集散') || titleLower.includes('集合')) return '🏠';
			if (titleLower.includes('交通') || titleLower.includes('出发')) return '🚗';
			if (titleLower.includes('活动') || titleLower.includes('体验') || titleLower.includes('插秧')) return '🌱';
			if (titleLower.includes('用餐') || titleLower.includes('餐')) return '🍽️';
			if (titleLower.includes('住宿') || titleLower.includes('休息')) return '🛏️';
			return '●';
		},
		// 切换折叠状态
		toggleFold() {
			this.isFold = !this.isFold;
		},

		// 切换天行程显示
		toggleDay(index) {
			if (this.mergedItineraries && this.mergedItineraries[index]) {
				this.mergedItineraries[index].show = !this.mergedItineraries[index].show;
				// 内容高度改变后重新缓存位置信息
				this.$nextTick(() => {
					this.cacheSectionPositions();
				});
			}
		},

		// 切换卡片折叠状态
		toggleCard(cardType) {
			this.cardFoldStates[cardType] = !this.cardFoldStates[cardType];
			// 内容高度改变后重新缓存位置信息
			this.$nextTick(() => {
				this.cacheSectionPositions();
			});
		},

		// 轮播图变更
		swiperChange(e) {
			this.swiperCurrent = e.detail.current;
		},

		// 预览图片
		previewImage(url) {
			uni.previewImage({
				urls: [url]
			});
		},

		// 退出预览
		exitPreview() {
			uni.navigateBack({ delta: 1 });
		},

		// 获取详情图标 - 使用uview图标名称
		getDetailIcon(type) {
			const iconMap = {
				'交通': 'car',
				'住宿': 'home',
				'餐饮': 'food',
				'活动': 'activity',
				'景点': 'map-pin'
			};
			return iconMap[type] || 'circle';
		},

		// 获取详情类型文本
		getDetailTypeText(type) {
			const typeMap = {
				'交通': '交通',
				'住宿': '住宿',
				'餐饮': '餐饮',
				'活动': '活动',
				'景点': '景点'
			};
			return typeMap[type] || '';
		},

		// 滚动到指定区域
		goToFloor(index) {
			this.navActive = index;
			this.floorNum = `f${index}`;
			this.scrollToId = `f${index}`;

			// 滚动后清空，防止无法重复触发
			setTimeout(() => {
				this.scrollToId = '';
			}, 500);
		},

		// 监听滚动
		scrollFloor(e) {
			// 可以根据滚动位置更新导航状态
			const scrollTop = e.detail.scrollTop;
			// 计算当前可视区域的主要内容，更新导航状态
			const query = uni.createSelectorQuery();
			query.selectAll('.product-section, .itinerary-section, .service-section, .notice-section').boundingClientRect();
			query.exec((res) => {
				if (res && res[0]) {
					for (let i = res[0].length - 1; i >= 0; i--) {
						if (res[0][i].top <= 100) {
							this.navActive = i;
							break;
						}
					}
				}
			});
		},
		// 获取地址名称（拆分后的第二部分，显示在上面）
		getAddressName(address) {
			if (!address) return '';
			if (address.includes('-')) {
				const parts = address.split('-');
				return parts[1] ? parts[1].trim() : '';
			}
			return '';
		},

		// 获取地址位置（拆分后的第一部分，显示在下面）
		getAddressLocation(address) {
			if (!address) return '';
			if (address.includes('-')) {
				const parts = address.split('-');
				return parts[0].trim();
			}
			return address; // 如果没有"-"，返回原地址
		},

		// 返回上一页
		backPage() {
			uni.navigateBack();
		},

		// 返回首页
		toHome() {
			uni.switchTab({
				url: '/pages/customer/index/index'
			});
		},




		// 切换预定须知项目展开状态
		toggleNoticeItem(itemType) {
			this.noticeItemStates[itemType] = !this.noticeItemStates[itemType];
		},

		// 切换条款项目展开状态
		toggleTermsItem(itemType) {
			this.termsItemStates[itemType] = !this.termsItemStates[itemType];
		},
		// 切换自定义提示单条展开状态
		toggleCustomizationItem(index) {
			const key = 'customization_' + index;
			this.noticeItemStates[key] = !this.noticeItemStates[key];
		},


		// 加入列表
		addToList() {
			uni.showToast({
				title: '已加入列表',
				icon: 'success'
			});
		},

		// 创建订单
		createOrder() {
			console.log('创建订单', this.periodList);
			console.log('创建订单', this.selectedDateIndex);
			if (this.selectedDateIndex === -1 && this.datelist.length > 0) {
				uni.showToast({
					title: '请先选择班期',
					icon: 'none'
				});
				return;
			}
			// 根据日期获取p1sId、p2sId、p3sId
			const p3sId = this.selectedDate.id;
			const date = this.selectedDate.DateName.split('-');
			// 根据selectedDate的日期在periodList中查找p1sId、p2sId
			// const period2 = this.periodList.p2s.filter(item => item.availableDate.yearDate === date[0] && item.availableDate.monthDate === date[1] && item.availableDate.dayDate === date[2]);
			let period2 = {}
			this.periodList[0].p2s.forEach(item => {
				if (item.availableDate.yearDate === date[0] && item.availableDate.monthDate === date[1] && item.availableDate.dayDate === date[2]) {
					period2 = item;
				}
			})
			const p2sId = period2.id;
			let period1 = {}
			this.periodList[0].p1s.forEach(item => {
				if (item.availableDate.yearDate === date[0] && item.availableDate.monthDate === date[1] && item.availableDate.dayDate === date[2]) {
					period1 = item;
				}
			})
			const p1sId = period1.id;
			console.log('p1sId', p1sId);
			console.log('p2sId', p2sId);
			console.log('p3sId', p3sId);
			// 跳转到订单页面
			uni.navigateTo({
				url: `/public/order/createOrder?spuId=${this.id}&p1sId=${p1sId}&p2sId=${p2sId}&p3sId=${p3sId}`,
			});
		},

		// 滚动监听（优化版本，使用节流）
		onScroll(e) {
			console.log('??e有计算吗', e, this.isScrollingToTarget)
			// 如果正在执行滚动动画，跳过部分更新以减少卡顿
			if (this.isScrollingToTarget) {
				return;
			}

			const scrollTop = e.detail.scrollTop;
			this.scrollTop = scrollTop;

			// 使用节流避免过于频繁的计算
			if (this.scrollTimer) {
				clearTimeout(this.scrollTimer);
			}
			console.log('有进这里吗')
			// 立即更新吸顶状态（这个计算很轻量）
			this.updateStickyStates(scrollTop);

			// 节流更新导航状态（这个计算较重）
			this.scrollTimer = setTimeout(() => {
				this.updateActiveNavOptimized(scrollTop);
			}, 32); // 约30fps的更新频率，降低计算频率
		},

		// 更新吸顶状态（轻量计算）
		updateStickyStates(scrollTop) {
			console.log('测试这里的呢', this.titleOriginalTop, this.navOriginalTop)
			// 判断产品标题是否需要吸顶
			if (this.titleOriginalTop > 0) {
				this.stickyTitle = scrollTop >= this.titleOriginalTop - 10;
			}

			// 判断导航栏是否需要吸顶：当其顶部与标题底部"相碰"时吸顶
			// 触发阈值提前到标题高度位置，使其固定在标题栏下方
			if (this.navOriginalTop > 0) {
				const titleHeight = this.titleHeightPx || 0;
				this.stickyNav = scrollTop >= (this.navOriginalTop - titleHeight);
			}
		},

		// 更新当前激活的导航项（原版本，保留作为备用）
		updateActiveNav() {
			const query = uni.createSelectorQuery().in(this);
			const sectionIds = this.navItems.map(item => item.id);

			// 获取所有区域的位置
			query.selectAll(sectionIds.map(id => `#${id}`).join(',')).boundingClientRect((rects) => {
				if (rects && rects.length > 0) {
					let activeIndex = 0;
					// 计算吸顶元素的总高度（px）
					const titleHeight = this.stickyTitle ? this.titleHeightPx : 0;
					const navHeight = this.stickyNav ? this.navHeightPx : 0;
					const extra = this.rpxToPx(50);
					const threshold = titleHeight + navHeight + extra;

					// 找到当前可视区域对应的导航项
					for (let i = 0; i < rects.length; i++) {
						if (rects[i] && rects[i].top <= threshold) {
							activeIndex = i;
						}
					}

					this.activeNavIndex = activeIndex;
				}
			});
			query.exec();
		},

		// 优化版本的导航项更新（使用缓存的位置信息）
		updateActiveNavOptimized(scrollTop) {
			// 避免不必要的计算
			if (Math.abs(scrollTop - this.lastScrollTop) < 5) {
				return; // 滚动距离太小，不需要更新
			}
			this.lastScrollTop = scrollTop;

			if (this.sectionPositions.length === 0) {
				return; // 位置信息未缓存
			}

			let activeIndex = 0;
			// 计算吸顶元素的总高度（px）
			const titleHeight = this.stickyTitle ? this.titleHeightPx : 0;
			const navHeight = this.stickyNav ? this.navHeightPx : 0;
			const extra = this.rpxToPx(50);
			const threshold = titleHeight + navHeight + extra;

			// 使用缓存的位置信息计算当前激活的导航项
			// 使用二分查找或简单遍历来找到当前区域
			for (let i = this.sectionPositions.length - 1; i >= 0; i--) {
				const sectionTop = this.sectionPositions[i].top - scrollTop;
				if (sectionTop <= threshold) {
					activeIndex = i;
					break;
				}
			}

			// 如果存在程序滚动指定的目标索引，则优先使用该索引
			const nextIndex = this.pendingTargetIndex >= 0 ? this.pendingTargetIndex : activeIndex;
			if (this.activeNavIndex !== nextIndex) {
				this.activeNavIndex = nextIndex;
			}
		},

		// 点击导航项滚动到对应区域
		scrollToSection(sectionId) {
			if (!sectionId) return;

			// 立即更新激活的导航索引
			const targetIndex = this.navItems.findIndex(item => item.id === sectionId);
			if (targetIndex >= 0) {
				this.activeNavIndex = targetIndex;
				this.pendingTargetIndex = targetIndex; // 锁定目标索引，避免中途被误判覆盖
			}

			const query = uni.createSelectorQuery().in(this);
			query.select(`#${sectionId}`).boundingClientRect((rect) => {
				if (rect) {
					// 计算吸顶元素的总高度作为偏移量（px）
					const titleHeight = this.cachedTitleHeightPx;
					const navHeight = this.cachedNavHeightPx;
					const extra = this.rpxToPx(20);
					const offset = titleHeight + navHeight + extra;

					// 计算目标滚动位置
					const targetScrollTop = Math.max(0, rect.top + this.scrollTop - offset);

					// 标记正在程序控制滚动，避免触发过多更新
					this.isScrollingToTarget = true;

					// 使用 scroll-with-animation 实现平滑滚动
					this.programScrollTop = targetScrollTop;

					// 300ms后恢复正常状态
					setTimeout(() => {
						this.isScrollingToTarget = false;
						this.pendingTargetIndex = -1; // 清除锁定
						// 滚动完成后再次确认激活状态（防止滚动过程中被覆盖）
						this.updateActiveNavOptimized(targetScrollTop);
					}, 300);
				}
			});
			query.exec();
		}
	}
};
</script>

<style lang="scss" scoped>
.product-info-container {
	background: #f8f8f8;
	padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
	height: 100vh;
	/* 优化滚动性能 */
	-webkit-overflow-scrolling: touch;
	will-change: scroll-position;
}

.card-content {
	padding: 20rpx;
	font-size: 28rpx;
	color: #333;
	line-height: 1.6;
}

/* 返回按钮 */
.back-btn {
	position: fixed;
	top: calc(env(safe-area-inset-top) + 30rpx);
	/* 状态栏安全区域高度 + 额外间距 */
	left: 30rpx;
	width: 72rpx;
	height: 72rpx;
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.55);
	/* 半透明黑底，深一点 */
	display: flex;
	justify-content: center;
	align-items: center;
	backdrop-filter: blur(8rpx);
	/* 毛玻璃效果 */
	box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.35);
	/* 阴影增强 */
	z-index: 999;
	/* 确保在最上层 */
	transition: background 0.2s;
}

.back-btn:active {
	background: rgba(255, 255, 255, 0.75);
}


.current {
	font-size: 26rpx;
}

.split {
	font-size: 24rpx;
	margin: 0 1rpx 0 2rpx;
}

.total {
	font-size: 26rpx;
}


/* 轮播图 */
.banner-container {
	position: relative;
}

.banner-swiper {
	width: 100%;
	height: 650rpx;
}

.banner-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.banner-placeholder {
	width: 100%;
	height: 650rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: #f5f5f5;
}

.banner-placeholder text {
	margin-top: 20rpx;
	font-size: 28rpx;
	color: #999;
}

.banner-info-bar {
	position: absolute;
	bottom: 0rpx;
	left: -1rpx;
	right: -1rpx;
	display: flex;
	justify-content: flex-start;
	background: rgba(0, 0, 0, 0.5);
	color: #fff;
	font-size: 26rpx;
	height: 106rpx;
	align-items: flex-start;
	padding-top: 30rpx;
}

.container-card {
	position: relative;
	bottom: 40rpx;
	/* padding-top: 20rpx; */
	background: #eeeeee;
	border-top-left-radius: 30rpx;
	border-top-right-radius: 30rpx;
	overflow: hidden;
}

.banner-info-bar .info-item {
	display: flex;
	align-items: center;
}

/* 公共卡片 */
.card {
	margin: 20rpx 0rpx;
	padding: 30rpx;
	background: #fff;
	border-radius: 5rpx;
	box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.05);
}


/* 标题 */
.title {
	font-size: 34rpx;
	font-weight: bold;
	color: #222;
}

.subtitle {
	font-size: 28rpx;
	color: #888;
	margin-bottom: 20rpx;
}

/* 渠道标签和价格 */
.channel-price-tag {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20rpx;
	margin-top: 20rpx;
}

.channel-tag {
	display: inline-block;
	padding: 8rpx 20rpx;
	background: #ffEEE1;
	border-radius: 8rpx;
	font-size: 24rpx;
	color: #f37b1d;
	font-weight: 500;
	letter-spacing: 1rpx;
}

.channel-text {
	font-size: 26rpx;
	color: #666666;
	font-weight: 400;
}

.price-integer {
	font-size: 32rpx;
	font-weight: 600;
	color: #333333;
}

.price-decimal {
	font-size: 24rpx;
	font-weight: 400;
	color: #666666;
}

.service-detail-text {
	font-size: 28rpx;
	color: #a0a0a0;
	white-space: nowrap;
}

.section-titles {
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 30rpx;
	font-weight: 600;
	color: #333;
	margin-left: 20rpx;
	margin-right: 20rpx;
}

.section-titles .title-left {
	display: flex;
	align-items: center;
}

/* 更多按钮 */
.more-btn {
	display: flex;
	align-items: center;
	padding: 8rpx 16rpx;
	background: rgba(255, 103, 0, 0.1);
	border-radius: 20rpx;
	cursor: pointer;
}

.more-text {
	font-size: 24rpx;
	color: #ff6700;
	margin-right: 6rpx;
}

/* Section标题 */
.section-title {
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 24rpx;
	font-weight: 600;
	color: #a0a0a0;

}

.section-title text {
	margin: auto;
}

/* 带线条的标题样式 */
.section-title-with-lines {
	display: flex;
	align-items: center;
	justify-content: center;
	padding-top: 20rpx;
}

.title-line {
	/* flex: 1; */
	height: 1rpx;
	background: #d0d0d0;
	margin: 0 30rpx;
	width: 200rpx;
	transform: scale(0.5);
}

.title-text {
	font-size: 28rpx;
	font-weight: 400;
	color: #999;
	white-space: nowrap;
}

/* 费用模块样式 */
.expense-section {
	margin-bottom: 20rpx;
}

.expense-section:last-child {
	margin-bottom: 0;
}

/* 费用标题样式 */
.expense-title {
	font-size: 28rpx;
	font-weight: bold;
	color: #ff6700;
	margin: 10rpx 0 10rpx 0;
	text-align: left;
}

/* 费用模块分隔线 */
.expense-divider {
	height: 1rpx;
	background: #e0e0e0;
	margin: 20rpx 0;
}

/* 预定须知项目头部样式 */
.expense-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10rpx 0;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	background: transparent;
}

.expense-header:active {
	background: transparent;
}

/* 预定须知项目内容样式 */
.expense-content {
	padding: 10rpx 0;
}

/* 预定须知箭头图标样式 */
.notice-arrow-icon {
	width: 40rpx;
	height: 40rpx;
	transition: transform 0.3s ease;
}

.notice-arrow-rotated {
	transform: rotate(180deg);
}



/* 价格 */
.price-box {
	margin-top: 20rpx;
	font-size: 30rpx;
}

.price {
	color: #ff4d4f;
	font-weight: bold;
}

.unit {
	font-size: 24rpx;
	color: #999;
	margin-left: 4rpx;
}

.no-price {
	color: #999;
}

/* Tab导航 */
.tab-nav {
	display: flex;
	border-bottom: 1rpx solid #eee;
}

.tab-item {
	flex: 1;
	text-align: center;
	padding: 20rpx 0;
	font-size: 28rpx;
	color: #666;
}

.tab-item.active {
	color: #ff6700;
	font-weight: 600;
	border-bottom: 4rpx solid #ff6700;
}

/* Tab内容 */
.tab-content {
	padding: 20rpx 0;
}

/* 产品特色容器 */
.features-container {
	transition: all 0.3s ease;
	overflow: hidden;
}


.features-container.collapsed {
	max-height: 500rpx;
	/* 约一个手机屏幕的高度 */
	position: relative;
}

.features-container.collapsed::after {
	content: '';
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
	height: 100rpx;
	background: linear-gradient(transparent, #fff);
	pointer-events: none;
	z-index: 1;
}

.feature-item {
	margin-bottom: 16rpx;
}

.feature-image {
	width: 100%;
	height: auto;
	border-radius: 12rpx;
	display: block;
}

.feature-text {
	font-size: 28rpx;
	color: #444;
	padding: 4rpx 40rpx;
}

.day-item {
	padding: 0rpx 20rpx 0rpx 0rpx;
}

.day-header {
	display: flex;
	align-items: center;
	padding: 20rpx 0;
	border-bottom: 1rpx solid #f0f0f0;
}

.day-badge {
	background: #20B2AA;
	color: #fff;
	padding: 12rpx 20rpx;
	border-top-right-radius: 5000rpx;
	border-bottom-right-radius: 5000rpx;
	font-size: 24rpx;
	font-weight: bold;
	margin-right: 20rpx;
	min-width: 60rpx;
	letter-spacing: 6rpx;
	text-align: center;
}

.day-content {
	flex: 1;
	display: flex;
	align-items: center;
}

.day-title {
	font-size: 32rpx;
	color: #333;
	/* line-height: 1.4; */
	flex: 1;
	font-weight: 700;
}

.day-arrow-icon {
	width: 40rpx;
	height: 40rpx;
	transition: transform 0.3s ease;
}

.day-arrow-rotated {
	transform: rotate(180deg);
}

.day-details {
	margin-top: 10rpx;
	color: #555;
	font-size: 26rpx;
}

/* 活动列表样式 */
.activity-list {
	padding: 0;
}

.activity-item {
	margin-bottom: 40rpx;
	padding-bottom: 20rpx;
	border-bottom: 1rpx solid #f0f0f0;
	padding: 0rpx 20rpx 20rpx 20rpx;
}

.activity-item:last-child {
	border-bottom: none;
	margin-bottom: 0;
}

.activity-header {
	display: flex;
	align-items: center;
	margin-bottom: 20rpx;
}

.activity-icon {
	font-size: 20rpx;
	margin-right: 20rpx;
	width: 24rpx;
	text-align: center;
	color: #666;
}

.activity-time {
	font-size: 36rpx;
	font-weight: bold;
	color: #333;
	margin-right: 20rpx;
	min-width: 100rpx;
}

.activity-title {
	font-size: 30rpx;
	font-weight: 600;
	color: #333;
	flex: 1;
}

.activity-details {
	margin-left: 44rpx;
}

.detail-item {
	margin-bottom: 16rpx;
	line-height: 1.5;
}

.detail-label {
	font-size: 26rpx;
	font-weight: bold;
	color: #333;
	display: inline;
}

.detail-text {
	font-size: 26rpx;
	color: #666;
	display: inline;
	margin-left: 8rpx;
}

.detail-label-icon {
	width: 28rpx;
	height: 28rpx;
}

.detail-address {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	flex: 1;
}

.detail-content {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-top: 8rpx;
}

.location-pin {
	font-size: 18rpx;
	color: #4CAF50;
	margin-left: 8rpx;
}

/* 信息行 */
.info-row {
	display: flex;
	padding: 12rpx 0;
	font-size: 28rpx;
}

.label {
	width: 180rpx;
	color: #666;
	font-size: 28rpx;
}

.value {
	flex: 1;
	color: #999;
}

/* 空内容 */
.empty-content {
	text-align: center;
	color: #aaa;
	font-size: 26rpx;
	padding: 20rpx 0;
}


/* 价格 */
.price-info {
	display: flex;
	align-items: baseline;
	font-weight: 600;
}

.price-symbol {
	font-size: 28rpx;
	color: #ff4d4f;
}

.price-value {
	font-size: 40rpx;
	color: #ff4d4f;
	margin: 0 6rpx;
}

.price-unit {
	font-size: 26rpx;
	color: #999;
}

/* 按钮组 */
.action-buttons {
	display: flex;
	align-items: center;
}

.btn-add,
.btn-order {
	padding: 0 36rpx;
	height: 76rpx;
	line-height: 76rpx;
	font-size: 28rpx;
	border-radius: 38rpx;
	font-weight: 500;
	border: none;
	margin-left: 16rpx;
}

/* 次按钮：加入列表 */
.btn-add {
	background: #f9f9f9;
	color: #333;
	border: 1rpx solid #ddd;
}

/* 主按钮：立即报名 */
.btn-order {
	background: linear-gradient(135deg, #ff6700, #ff914d);
	color: #fff;
	box-shadow: 0 4rpx 10rpx rgba(255, 103, 0, 0.3);
}

/* 展开按钮 */
.expand-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	margin-top: 20rpx;
	padding: 16rpx 0;
	cursor: pointer;
}

.expand-text {
	font-size: 24rpx;
	color: #ff6700;
	margin-right: 8rpx;
}

/* 产品标题容器 */
.title-container {
	padding: 30rpx;
	background: #fff;
	border-radius: 5rpx;
	box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.05);
	z-index: 998;
}


.title-container.sticky-title {
	position: fixed;
	/* top 通过内联样式控制，不使用安全区域 */
	left: 0;
	right: 0;
	margin: 0;
	border-radius: 0;
	box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
	border-bottom: 1rpx solid #f0f0f0;
	/* 优化固定定位性能 */
	transform: translateZ(0);
	will-change: transform;
}

/* 产品标题占位元素 */
.title-placeholder {
	height: 120rpx;
	margin: 20rpx;
}

/* 导航栏容器 */
.nav-container {
	margin: 20rpx 0rpx;
	padding: 0rpx 20rpx;
	height: 80rpx;
	background: #fff;
	border-radius: 5rpx;
	box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.05);
	display: flex;
	z-index: 999;
}

.nav-container.sticky-nav {
	position: fixed;
	/* top 通过内联样式控制，位于标题下方 */
	left: 0;
	right: 0;
	margin: 0;
	border-radius: 0;
	box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
	border-bottom: 1rpx solid #f0f0f0;
	/* 优化固定定位性能 */
	transform: translateZ(0);
	will-change: transform;
}

.nav-item {
	flex: 1;
	text-align: center;
	padding: 20rpx 10rpx;
	font-size: 26rpx;
	color: #666;
	position: relative;
	transition: color 0.3s ease;
}

.nav-item.active {
	color: #ff6700;
	font-weight: 600;
}

.nav-item.active::after {
	content: '';
	position: absolute;
	bottom: 0;
	left: 50%;
	transform: translateX(-50%);
	width: 40rpx;
	height: 4rpx;
	background: #ff6700;
	border-radius: 2rpx;
}

/* 导航栏占位元素 */
.nav-placeholder {
	height: 80rpx;
	margin: 20rpx;
}

/* 班期选择弹出层样式 */
.date-modal {
	background: #fff;
	padding: 0;
	max-height: 70vh;
}

.modal-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 30rpx;
	border-bottom: 1rpx solid #f0f0f0;
}

.modal-title {
	font-size: 32rpx;
	font-weight: 600;
	color: #333;
}

.close-btn {
	width: 60rpx;
	height: 60rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: #f8f8f8;
}

.modal-content {
	padding: 30rpx;
	max-height: 50vh;
	overflow-y: auto;
}

.date-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 20rpx;
}

.date-item {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 20rpx;
	border: 2rpx solid #f0f0f0;
	border-radius: 12rpx;
	background: #fff;
	cursor: pointer;
	transition: all 0.3s ease;
}

.date-item.active {
	border-color: #ff6700;
	background: rgba(255, 103, 0, 0.05);
}

.date-day {
	font-size: 28rpx;
	font-weight: 600;
	color: #333;
	margin-bottom: 8rpx;
}

.date-item.active .date-day {
	color: #ff6700;
}

.date-week {
	font-size: 24rpx;
	color: #999;
	margin-bottom: 8rpx;
}

.date-item.active .date-week {
	color: #ff6700;
}

.date-price {
	font-size: 22rpx;
	color: #ff4d4f;
	font-weight: 500;
}

.modal-footer {
	padding: 30rpx;
	border-top: 1rpx solid #f0f0f0;
}

.confirm-btn {
	width: 100%;
	height: 88rpx;
	background: linear-gradient(135deg, #ff6700, #ff914d);
	color: #fff;
	border: none;
	border-radius: 44rpx;
	font-size: 32rpx;
	font-weight: 600;
}

/* 预览页面提示 */
.preview-notice {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	display: flex;
	align-items: center;
	padding: 30rpx;
	padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
	background: linear-gradient(135deg, #fff5f0, #ffe8d6);
	border-top: 2rpx solid #ff6700;
	box-shadow: 0 -4rpx 12rpx rgba(255, 103, 0, 0.1);
	z-index: 1000;
	/* 确保在所有设备上都能正常显示 */
	min-height: 120rpx;
	box-sizing: border-box;
}

.preview-icon {
	margin-right: 20rpx;
	padding: 16rpx;
	background: rgba(255, 103, 0, 0.1);
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
}

.preview-text {
	flex: 1;
	display: flex;
	flex-direction: column;
}

.preview-title {
	font-size: 32rpx;
	font-weight: 600;
	color: #ff6700;
	margin-bottom: 8rpx;
}

.preview-desc {
	font-size: 26rpx;
	color: #666;
	line-height: 1.4;
}

.exit-preview-btn {
	margin-left: 20rpx;
	padding: 16rpx 28rpx;
	background: linear-gradient(135deg, #ff8333, #ff6700);
	color: #fff;
	border-radius: 44rpx;
	font-size: 28rpx;
	font-weight: 600;
	box-shadow: 0 4rpx 12rpx rgba(255, 103, 0, 0.25);
	min-width: 168rpx;
	text-align: center;
}

.itinerary-detail-item {
	margin-bottom: 30rpx;
	padding-bottom: 20rpx;
	border-bottom: 1rpx solid #f0f0f0;
}

.itinerary-detail-item:last-child {
	border-bottom: none;
	margin-bottom: 0;
}

.item-time-container {
	display: flex;
	align-items: center;
	// margin-bottom: 16rpx;
	margin-left: 20rpx;
}

.item-time {
	font-size: 28rpx;
	font-weight: bold;
	color: #333;
	margin-right: 10rpx;
}

.item-type {
	font-size: 28rpx;
	color: #666;
}

.item-separator {
	margin: 0 10rpx;
	color: #999;
}

.item-name {
	font-size: 28rpx;
	color: #666;
	font-weight: 500;
}

/* 地址显示样式 */
.address-display {
	display: flex;
	flex-direction: column;
	gap: 4rpx;
}

.address-name {
	font-size: 26rpx;
	color: #333;
	font-weight: 700;
	line-height: 1.4;
}

.address-location {
	font-size: 24rpx;
	color: #666;
	line-height: 1.4;
	margin-left: 0;
}

.item-details {
	margin-left: 20rpx;
	margin-bottom: 20rpx;
	margin-top: 20rpx;
}

.item-detail-row {
	display: flex;
	// margin-bottom: 10rpx;
	font-size: 24rpx;
	line-height: 1.5;
}

.detail-label {
	color: #999;
	margin-right: 20rpx;
	min-width: 70rpx;
	display: flex;
	align-items: flex-start;
	justify-content: flex-end;

	.detail-label-icon {
		width: 28rpx;
		height: 28rpx;
		// margin-top:6rpx;
	}
}

.server-title {
	font-weight: 700;
	color: #000000;
	font-size: 30rpx;
	margin-bottom: 20rpx;
	// margin-left: 20rpx;
}

.serve-box {
	display: flex;
	align-items: flex-start;
	margin-top: 20rpx;
	color: #999999;
}

.serve-title {
	font-size: 28rpx;
	width: 200rpx;
}

.serve-content {
	font-size: 28rpx;
}
</style>